﻿// ==================================================================================================
// Copyright(C) 2012 NCS Pte. Ltd. All rights reserved.
//
// SYSTEM NAME	    : iConnect .Net Application Framework
// COMPONENT ID	    : NCS.IConnect.Core
// COMPONENT DESC   : The foundation component of the whole framework. 	
//
// CREATED DATE/BY  : 13 Apr 2012 / Wu Yong Qing
//
// REVISION HISTORY :	
// DATE/BY			SR#/CS/PM#/OTHERS		DESCRIPTION OF CHANGE
// ==================================================================================================


using NCS.IConnect.Core.Utilities;
using System;
using System.Collections.Generic;

namespace NCS.IConnect.Core.IoC.TransientCall
{
    /// <summary>
    /// Transient call interceptor
    /// </summary>
    public class DefaultTransientCallInterceptor : ITransientCallInterceptor
    {
        private static readonly Dictionary<Type, Type> interceptClasses = new Dictionary<Type, Type>();

        /// <summary>
        /// Determines whether this instance can intercept the specified type.
        /// </summary>
        /// <param name="type">The type.</param>
        /// <returns>
        ///   <c>true</c> if this instance can intercept the specified type; otherwise, <c>false</c>.
        /// </returns>
        public bool CanIntercept(Type type)
        {
            Guard.ArgumentNotNull(type, "type");
            return type.IsInterface;
        }

        /// <summary>
        /// Creates the proxy.
        /// </summary>
        /// <param name="type">The type.</param>
        /// <param name="instanceProvider">The instance provider.</param>
        /// <returns>Transient call interceptor</returns>
        public object CreateProxy(Type type, IInstanceProvider instanceProvider)
        {
            Guard.ArgumentNotNull(type, "type");
            Guard.ArgumentNotNull(instanceProvider, "instanceProvider");

            Type typeGen;
            Type baseType = type;
            bool flag = false;

            if(type.IsGenericType)
            {
                baseType = type.GetGenericTypeDefinition();
                flag = true;
            }

            lock (interceptClasses)
            {
                if (!interceptClasses.TryGetValue(baseType, out typeGen))
                {
                    typeGen = new TransientCallProxyClassGenerator(baseType).CreateProxyType();
                    interceptClasses[baseType] = typeGen;
                }
            }
            if(flag)
            {
                typeGen = typeGen.MakeGenericType(type.GetGenericArguments());
            }

            return typeGen.GetConstructors()[0].Invoke(new object[] { instanceProvider });
        }
    }
}